#include "user_mb_data_process.h"

/**
 * @desc  : 从机输入寄存器自定义回调函数
 * @date  : 2025-10-29
 * @author: AnRui
 * @param : reg_addr - 输入寄存器协议地址（1-based）
 * @param : data_buff - 输入寄存器缓冲区（指向usSRegInBuf）
 * @param : index - 该寄存器在输入寄存器缓冲区的索引
 * @note  : 自定义更新输入寄存器缓冲区，为主机读取（功能码04）准备实时数据
 */
void eMBRegInputCallBackFunc(uint16_t reg_addr, uint16_t* data_buff, uint16_t index)
{
    printf("Input addr %02x ,index %d\r\n", reg_addr, index);
    // 根据输入寄存器地址，执行硬件数据采集并更新缓冲区
    switch (reg_addr) {
    case 0x01:
        // 【需替换】实际硬件数据采集（如模拟量传感器ADC读取：data_buff[index] = ADC_GetValue(ADC_CH0);） 
        data_buff[index] = 30;
        break;
    case 0x02:
        // 【需替换】实际硬件数据采集（如温度传感器读取：data_buff[index] = DS18B20_GetTemp();） 
        data_buff[index] = 90;
        break;
    default:
        break;
    }
}

/**
 * @desc  : 从机保持寄存器读数据的自定义回调函数
 * @date  : 2025-10-29
 * @author: AnRui
 * @param : reg_addr - 保持寄存器协议地址（1-based）
 * @param : data_buff - 保持寄存器缓冲区（指向usSRegHoldBuf）
 * @param : index - 该寄存器在保持寄存器缓冲区的索引
 * @note  : 自定义更新保持寄存器缓冲区，为主机读取（功能码03）准备状态/参数数据
 */
void eMBRegHoldingReadCallBackFunc(uint16_t reg_addr, uint16_t* data_buff, uint16_t index)
{
    printf("hold read addr %02x ,index %d\r\n", reg_addr, index);
    // 根据保持寄存器地址，更新缓冲区数据（如设备状态、配置参数）
    switch (reg_addr) {
    case 0x01:
        // 【需替换】实际设备状态读取（如CPU使用率：data_buff[index] = Get_CPU_Usage_Major();）
        data_buff[index] = 100;  // 临时模拟值，需替换为实际状态值
        break;
    case 0x02:
        // 【需替换】实际设备参数读取（如波特率配置：data_buff[index] = USART_GetBaudRate(USART1);）
        data_buff[index] = 101;  // 临时模拟值，需替换为实际参数值
        break;
    default:
        break;
    }
}

/**
 * @desc  : 从机保持寄存器写数据的自定义回调函数
 * @date  : 2025-10-29
 * @author: AnRui
 * @param : reg_addr - 保持寄存器协议地址（1-based）
 * @param : data - 主机下发的16bit控制参数/配置值
 * @note  : 根据主机下发数据执行硬件控制或参数保存（如写入硬件寄存器、更新配置）
 */
void eMBRegHoldingWriteCallBackFunc(uint16_t reg_addr, uint16_t data)
{
    printf("hold write addr %02x ,data %d\r\n", reg_addr, data);
    // 根据保持寄存器地址，执行对应硬件控制或参数保存
    switch (reg_addr) {
    case 0x01:
        // 【需替换】实际硬件配置（如设置PWM占空比：TIM_SetCompare(TIM1, TIM_Channel_1, data);）
        break;
    case 0x02:
        // 【需替换】实际参数保存（如保存波特率到Flash：Flash_SaveBaudRate(data);）
        break;
    default:
        break;
    }
    return;
}

/**
 * @brief  线圈读操作回调函数：遍历每个线圈地址，同步硬件状态到缓冲区
 * @details 针对主机读线圈(功能码01)请求，逐个处理每个线圈地址：
 *          1. 根据协议地址读取对应硬件状态(0=无效/关，1=有效/开)；
 *          2. 按bit位更新线圈缓冲区，确保缓冲区与硬件状态一致；
 *          3. 自动处理字节切换(bit索引0~7循环，满8位切换到下一个字节)。
 * @param  reg_addr - 起始线圈协议地址(1-based，与主机请求地址一致)
 * @param  data_buff - 线圈缓冲区指针(uint8_t类型，1字节=8个线圈bit位)
 * @param  index - 起始字节索引(data_buff的数组下标)
 * @param  bit_index - 起始bit索引(0~7)
 * @param  num - 需处理的线圈总数
 * @note   未定义地址用value=0xFF标记，不修改缓冲区；硬件API需根据实际芯片替换。
 */
void eMBRegCoilsReadCallBackFunc(uint16_t reg_addr, uint8_t* data_buff,
    uint16_t index, uint16_t bit_index, uint16_t num)
{
    uint8_t value = 0;
    uint16_t current_index = index;    // 临时变量：避免修改入参
    uint16_t current_bit = bit_index;  // 临时变量：避免修改入参
    uint16_t remaining_num = num;      // 临时变量：避免修改入参

    // 遍历所有需处理的线圈，同步硬件状态到缓冲区
    while (remaining_num > 0) {
        printf("coil read addr %02x ,index: %d bit_index: %d \r\n", reg_addr, current_index, current_bit);
        // 根据协议地址读取硬件实时状态
        switch (reg_addr) {
        case 0x01:  // 协议地址0x01 → 继电器状态反馈
            // 【需替换】实际硬件读取（如GPIO电平：value = gpio_input_bit_get(GPIOC, GPIO_PIN_0);）
            value = 1; // 临时模拟：继电器开启
            break;

        case 0x02:  // 协议地址0x02 → 指示灯状态反馈 
            // 【需替换】实际硬件读取（如GPIO电平：value = gpio_input_bit_get(GPIOC, GPIO_PIN_1);）
            value = 1; // 修正：线圈状态仅0/1，模拟指示灯熄灭
            break;

        default:  // 未定义地址：不更新缓冲区
            value = 0xFF;
            break;
        }

        // 仅在地址定义时更新缓冲区
        if (value == 0) {
            data_buff[current_index] &= ~(1 << current_bit);
        } else if (value == 1) {
            data_buff[current_index] |= (1 << current_bit);
        }

        // 更新参数，准备处理下一个线圈
        reg_addr++;
        current_bit++;
        if (current_bit == 8) {
            current_index++;
            current_bit = 0;
        }
        remaining_num--;
    }
}

/**
 * @brief  线圈写操作回调函数：根据本地缓冲区新值控制硬件
 * @param  reg_addr - 起始线圈协议地址（1-based）
 * @param  data_buff - 本地线圈缓冲区（已写入主机下发的值）
 * @param  start_index - 起始字节索引
 * @param  start_bit - 起始bit索引（0~7）
 * @param  num - 需处理的线圈总数
 */
void eMBRegCoilsWriteCallBackFunc(uint16_t reg_addr, uint8_t* data_buff,
    uint16_t start_index, uint16_t start_bit, uint16_t num)
{
    uint16_t current_index = start_index;  // 当前字节索引
    uint16_t current_bit = start_bit;      // 当前bit索引
    uint8_t  coil_value = 0;               // 线圈控制值（0=关，1=开）
    uint16_t remaining_num = num;          // 临时变量：避免修改入参

    // 遍历所有需处理的线圈，执行硬件控制
    while (remaining_num > 0) {
        // 从缓冲区提取线圈控制值
        coil_value = (data_buff[current_index] >> current_bit) & 0x01;
        printf("coil write addr %02x ,index: %d bit_index: %d data:%d \r\n", reg_addr, current_index, current_bit, coil_value);
        // 根据协议地址执行硬件控制
        switch (reg_addr) {
        case 0x01:  // 协议地址0x01 → 继电器控制
            // 【需替换】实际硬件控制（如GPIO输出：coil_value ? gpio_bit_set(GPIOC, GPIO_PIN_0) : gpio_bit_reset(GPIOC, GPIO_PIN_0);）
            printf("Coil 0x01 control: %02x\n", coil_value);
            break;

        case 0x02:  // 协议地址0x02 → 指示灯控制
            // 【需替换】实际硬件控制（如GPIO输出：coil_value ? gpio_bit_set(GPIOC, GPIO_PIN_1) : gpio_bit_reset(GPIOC, GPIO_PIN_1);）
            printf("Coil 0x02 control:%02x\n", coil_value);
            break;

        default:
            break;
        }

        // 更新参数，准备处理下一个线圈
        reg_addr++;
        current_bit++;
        if (current_bit == 8) {
            current_index++;
            current_bit = 0;
        }
        remaining_num--;
    }
}

/**
 * @brief  离散输入同步函数：同步硬件状态到本地缓冲区
 * @param  reg_addr - 起始离散输入协议地址（1-based）
 * @param  data_buff - 离散输入缓冲区指针（uint8_t类型，1字节=8个bit位）
 * @param  start_index - 起始字节索引
 * @param  start_bit - 起始bit索引（0~7）
 * @param  num - 需处理的离散输入总数
 */
void eMBRegDiscreteReadCallBackFunc(uint16_t reg_addr, uint8_t* data_buff,
    uint16_t start_index, uint16_t start_bit, uint16_t num)
{
    uint16_t current_index = start_index;  // 当前字节索引
    uint16_t current_bit = start_bit;      // 当前bit索引
    uint8_t  hardware_state = 0;           // 硬件状态（0=未触发，1=已触发）
    uint16_t remaining_num = num;          // 临时变量：避免修改入参

    // 遍历所有需处理的离散输入，同步硬件状态到缓冲区
    while (remaining_num > 0) {
        printf("dist read addr %02x ,index: %d bit_index: %d\r\n", reg_addr, current_index, current_bit);
        // 根据协议地址读取硬件实时状态
        switch (reg_addr) {
        case 0x01:  // 协议地址0x01 → 按键状态（下拉输入）
            // 【需替换】实际硬件读取（如按键引脚：hardware_state = !gpio_input_bit_get(GPIOA, GPIO_PIN_0);）
            hardware_state = 1;  // 临时模拟：按键未按下
            break;

        case 0x02:  // 协议地址0x02 → 故障检测（上拉输入，低电平触发）
            // 【需替换】实际硬件读取（如故障引脚：hardware_state = !gpio_input_bit_get(GPIOA, GPIO_PIN_1);）
            hardware_state = 1;  // 临时模拟：设备故障
            break;

        default:  // 未定义地址：不更新缓冲区
            hardware_state = 0xFF;
            break;
        }

        // 仅在地址定义时更新缓冲区
        if (hardware_state == 0) {
            data_buff[current_index] &= ~(1 << current_bit);
        } else if (hardware_state == 1) {
            data_buff[current_index] |= (1 << current_bit);
        }

        // 更新参数，准备处理下一个离散输入
        reg_addr++;
        current_bit++;
        if (current_bit == 8) {
            current_index++;
            current_bit = 0;
        }
        remaining_num--;
    }
}
